#ifndef _MANAGER_H_
#define _MANAGER_H_

#include <map>
#include <utility>

#include "singleton.hpp"

namespace Medved
{

class Managed;

class Manager
{
public:
	class badGet{};

	Manager() :
		counter_(0)
	{}

	int put(Managed *item)
	{
		m_.insert(std::make_pair(counter_, item));
		return counter_++;
	}

	void dublicate(int id, Managed *item)
	{
		m_.insert(std::make_pair(id, item));
	}

	Managed *get(int id)
	{
		typedef std::multimap<int, Managed *>::const_iterator Iter;

		std::pair<Iter, Iter> bounds = m_.equal_range(id);
		Managed *ret;

		ret = bounds.first->second;
		if (bounds.first == bounds.second)
			// no such Managed
			return 0;
		else if (++bounds.first != bounds.second) // more than one Managed
			throw badGet();
		return ret;
	}

	void remove(int id, Managed *item)
	{
		typedef std::multimap<int, Managed *>::iterator Iter;

		std::pair<Iter, Iter> bounds = m_.equal_range(id);
		for (; bounds.first != bounds.second; ++bounds.first)
			if (bounds.first->second == item) {
				m_.erase(bounds.first);
				break;
			}
	}
private:
	std::multimap<int, Managed *> m_;
	int counter_;
};

typedef Singleton<Manager> TheManager;



class Managed
{
protected:
	int id;

	Managed()
	{
		id  = TheManager::instance().put(this);
	}

	Managed(const Managed& rhs) : id(rhs.id)
	{
		TheManager::instance().dublicate(id, this);
	}
	
	Managed &operator =(const Managed &rhs)
	{
		TheManager::instance().remove(id, this);
		id = rhs.id;
		TheManager::instance().dublicate(id, this);
		return *this;
	}

	~Managed()
	{
		TheManager::instance().remove(id, this);
		id = -1;
	}
public:
	int getId() const { return id; }
};

}

#endif
